package awk.thread;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.concurrent.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


/**
 * 应用模块名称<p>
 * 代码描述<p>
 * created with IDEA
 *
 * @author haifeng.wang
 * @since 2019/4/1 16:32
 * <p>
 * 1.Apache commons-lang3 提供的 BasicThreadFactory.
 * ThreadFactory customizableThreadFactory = new BasicThreadFactory.Builder().namingPattern("customer-").build();
 * <p>
 * 2.Google guava 工具类 提供的 ThreadFactoryBuilder ,使用链式方法创建。
 * ThreadFactory customizableThreadFactory = new ThreadFactoryBuilder().setNameFormat("retryClient-pool-").build();
 * <p>
 * <p>
 * 3.Spring 框架提供的 CustomizableThreadFactory。
 * ThreadFactory customizableThreadFactory = new CustomizableThreadFactory("customer-");
 * ((CustomizableThreadFactory)customizableThreadFactory).setThreadGroupName("customer-group-");
 * <p>
 * 4.、Executors 创建线程池
 * Executors.newFixedThreadPool(10) 和 Executors.newSingleThreadExecutor(): 主要问题是堆积的请求处理队列可能会耗费非常大的内存，甚至OOM。
 * Executors.newScheduledThreadPool: 主要问题是线程数最大数是Integer.MAX_VALUE，可能会创建数量非常多的线程，甚至OOM。
 * Executors.newCachedThreadPool();创建一个可缓存线程池，如果线程池长度超过处理需要，可灵活回收空闲线程，若无可回收，则新建线程。
 * Executors.newSingleThreadExecutor();创建一个定长线程池，支持定时及周期性任务执行。
 * ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,customizableThreadFactory);
 * ExecutorService 是 Executor 的子类,ThreadPoolExecutor 是 ExecutorService的子类
 * ExecutorService executor = Executors.newFixedThreadPool(4);
 * Executor executor = Executors.newCachedThreadPool();
 */
public class ThreadPoolUtils {


    public static ThreadPoolExecutor getPool(){
        //ExecutorService 是 Executor 的子类,ThreadPoolExecutor 是 ExecutorService的子类
        //ExecutorService executor = Executors.newFixedThreadPool(4);

        /**
         * 一般来说，这里的阻塞队列有以下几种选择：
         *   ArrayBlockingQueue;（使用较少）
         *   PriorityBlockingQueue（使用较少）
         *   LinkedBlockingQueue;
         *   SynchronousQueue;（推荐）
         *   LinkedBlockingDeque（推荐）
         *
         * LinkedBlockingDeque是一个由链表结构组成的双向阻塞队列，即可以从队列的两端插入和移除元素。双向队列因为多了一个操作队列的入口，
         * 在多线程同时入队时，也就减少了一半的竞争。
         * 相比于其他阻塞队列，LinkedBlockingDeque多了addFirst、addLast、peekFirst、peekLast等方法，以first结尾的方法，表示插入、
         * 获取获移除双端队列的第一个元素。以last结尾的方法，表示插入、获取获移除双端队列的最后一个元素。
         * LinkedBlockingDeque是可选容量的，在初始化时可以设置容量防止其过度膨胀，如果不设置，默认容量大小为Integer.MAX_VALUE。
         */
        LinkedBlockingDeque<Runnable> linkedBlockingDeque = new LinkedBlockingDeque<Runnable>(20);

        ThreadFactory customizableThreadFactory = new ThreadFactoryBuilder().setNameFormat("retryClient-pool-").build();
        /**
         *         拒绝处理任务时的策略，有以下四种取值：
         *         ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
         *         ThreadPoolExecutor.DiscardPolicy：也是丢弃任务，但是不抛出异常。
         *         ThreadPoolExecutor.DiscardOldestPolicy：丢弃队列最前面的任务，然后重新尝试执行任务（重复此过程）
         *         ThreadPoolExecutor.CallerRunsPolicy：由调用线程处理该任务
         */
        ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,customizableThreadFactory);
        /**
         * scheduleAtFixedRate 指的是“以固定的频率”执行，period（周期）指的是两次成功执行之间的时间。 上一个任务开始的时间计时，一个period后，
         * 检测上一个任务是否执行完毕，如果上一个任务执行完毕，则当前任务立即执行，如果上一个任务没有执行完毕，则需要等上一个任务执行完毕后立即执行。
         * FixedRate: 固定比率 本test现象：执行完，没有歇息，直接开始下一次。
         */
        executorService.scheduleAtFixedRate(()-> System.out.println("hello"),5,2,TimeUnit.SECONDS);
        executorService.scheduleWithFixedDelay(()-> System.out.println("hello"),5,2,TimeUnit.SECONDS);

        return new ThreadPoolExecutor(10, 20, 100, TimeUnit.SECONDS, linkedBlockingDeque, customizableThreadFactory,
                new ThreadPoolExecutor.AbortPolicy());
    }


    public void test() {
        ThreadPoolExecutor threadPoolExecutor = getPool();
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + "拿到锁了111");
                    System.out.println(Thread.currentThread().getName() + "等待信号111");
                    condition.await();
                    System.out.println(Thread.currentThread().getName() + "拿到信号111");
                } catch (Exception e) {

                } finally {
                    lock.unlock();
                }
            }
        });

        threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + "拿到锁了222");
                    condition.signal();
                    System.out.println(Thread.currentThread().getName() + "发出信号222");
                } catch (Exception e) {

                } finally {
                    lock.unlock();
                }
            }
        });
    }
}
